from django.shortcuts import get_object_or_404, render
from django.utils import timezone
from django.views import generic
from django.db import connection
from django.http import HttpResponse
from source.Lib.Tools import Outer

import re
import json
import hashlib
import datetime
from pprint import pprint
# Create your views here.


def home(request):
    dtHtmlArgs = dict()
    dtHtmlArgs['HomeNavbar'] = True
    return render(request, 'Configuration/home.html', dtHtmlArgs)


def get_match(request):
    cli = Outer.get_cli()
    req_args = get_post_args(request.POST)
    result = []
    for key in cli.keys(f"{req_args['redis_key']}:*"):
        result.append(bytes(cli.get(key)).decode())
        cli.delete(key)
    return HttpResponse(json.dumps(result), content_type="application/json")


def get_simulate(request):
    cli = Outer.get_cli()
    req_args = get_post_args(request.POST)
    if not cli.get(req_args['redis_key']):
        return HttpResponse(json.dumps({'ret': False, 'msg': 'wait sec'}), content_type="application/json")
    body = bytes(cli.get(req_args['redis_key'])).decode()
    data = json.loads(body)
    if data['ret']:
        for code in data['data']['quota']:
            sources = list(data['data']['quota'][code][0].keys())
            chinese = SwitchKeyWord([" ".join(sources), ], False)[1]
            dictional = {}
            for i in range(0, len(chinese)):
                dictional[sources[i]] = chinese[i]
            new_dt = dict()
            for dt in data['data']['quota'][code]:
                for q in dt:
                    quota_chinese = dictional[q]
                    if dt[q] and 'None' not in dt[q]:
                        value = round(float(dt[q]), 1)
                        new_dt.setdefault(quota_chinese, list())
                        new_dt[quota_chinese].append(value)
            label = list()
            rows = list()
            for i in new_dt:
                label.append(i)
                rows.append(new_dt[i])
            data['data']['quota'][code] = {'label': label, 'rows': rows}
    return HttpResponse(json.dumps(data), content_type="application/json")


def get_post_args(dt):
    args = {
        'mode_code': {
            'key': dt.get('mode_code[key]'),
            'value': dt.get('mode_code[value]')
        },
        'mode_time': {
            'key': dt.get('mode_time[key]'),
            'value': dt.get('mode_time[value]')
        },
        'buy_rate': dt.get('buy_rate'),
        'sell_rate': dt.get('sell_rate'),
        'up': dt.get('up'),
        'down': dt.get('down'),
        'money': dt.get('money'),
        'strategy': dt.get('strategy'),
        'formulas': dt.get('formulas')
    }
    args['redis_key'] = "Simulation:"+hashlib.md5(json.dumps(args).encode()).hexdigest()
    if isinstance(args['formulas'], str) and '|' in args['formulas']:
        args['formulas'] = args['formulas'].split('|')
    else:
        formulas = []
        for formula in eval(args['formulas']):
            formulas.append(' '.join([item['name'] for item in formula]))
            args['formulas'] = formulas
    return args


def match(request):
    cli = Outer.get_cli()
    req_args = get_post_args(request.POST)
    cli.publish('SimulationMatch', json.dumps(req_args))
    return HttpResponse(json.dumps({'msg': 'success', 'ret': 0}), content_type="application/json")


def simulate(request):
    cli = Outer.get_cli()
    req_args = get_post_args(request.POST)
    cli.publish('SimulationSignal', json.dumps(req_args))
    return HttpResponse(json.dumps({'msg': 'success', 'ret': 0}), content_type="application/json")


def strategy(request):
    dtHtmlArgs = dict()
    dtHtmlArgs['TextName'] = "策略名称"
    dtHtmlArgs['StrategyNarbar'] = True
    dtHtmlArgs['TextLabel'] = """公式注意事项：
    0. 输入$(报表),&(行情),@(指标)：＋中文+TAB匹配对应信息
    1. 只支持Python支持的运算符号：+,-,*,/,%,**,()
    2. 只支持Python支持的逻辑符号：<,<=,>,>=,==,!=
    3. 操作符和操作数之间必须使用空格做间隔"""
    dtHtmlArgs["TextLabelRows"] = len(dtHtmlArgs['TextLabel'].split('\n'))
    return render(request, 'Configuration/config.html', dtHtmlArgs)


def quota(request):
    dtHtmlArgs = dict()
    dtHtmlArgs['TextName'] = "指标名称"
    dtHtmlArgs['QuotaNarbar'] = True
    dtHtmlArgs['TextLabel'] = """公式注意事项：
    0. 输入$(报表),&(行情),@(指标)：＋中文+TAB匹配对应信息
    1. 只支持Python支持的运算符号：+,-,*,/,%,**,()
    2. 操作符和操作数之间必须使用空格做间隔"""
    dtHtmlArgs["TextLabelRows"] = len(dtHtmlArgs['TextLabel'].split('\n'))
    return render(request, 'Configuration/config.html', dtHtmlArgs)


def Complete(request):
    msg = f"{request.POST.get('quota')}:{request.POST.get('code')}:{request.POST.get('date')}"
    cli = Outer.get_cli()
    cli.publish('MarketUpdateSignal', msg)
    return HttpResponse(json.dumps({'msg': 'success', 'ret': 0}), content_type="application/json")


def Recal(request):
    quota_id = request.POST.get('quota')
    code = request.POST.get('code')
    cli = Outer.get_cli()
    cli.publish('MarketUpdateSignal', f"{quota_id}:{code}:recal")
    return HttpResponse(json.dumps({'ret': True}), content_type="application/json")


def QuotaHistory(request):
    quota_id = request.POST.get('quota')
    code = request.POST.get('code')
    cli = Outer.get_cli()
    try:
        history = json.loads(cli.get(f"QuotaData:{quota_id}:{code}").decode())
        dates = sorted(history.keys())
        values = list()
        for i in dates:
            values.append(history[i])
        return HttpResponse(json.dumps({'ret': True, 'xAxis': dates, 'series': values}), content_type="application/json")
    except (AttributeError, ):
        return HttpResponse(json.dumps({'ret': False}), content_type="application/json")


def QueryPageDB(request):
    sortName = 'create_time' if request.GET.get('sortName') == 'time' else request.GET.get('sortName')
    sortOrder = request.GET.get('sortOrder')
    searchText = request.GET.get('searchText', '')

    ltFilterFormula = list(map(lambda x: f"'{x}'", SwitchKeyWord(request.GET.getlist('formula[]'))[0]))
    if ltFilterFormula:
        formulaCondition = f"b.success @> ARRAY[{','.join(ltFilterFormula)}]"
    else:
        formulaCondition = "true"

    cursor = connection.cursor()
    cursor.execute(f"""
        select 
            b.id, a.name, b.status, b.schedule, 
            concat(c.name, '(', c.code, ')'), 
            b.success, b.failed, b.create_time, b.quota_result
        from 
            t_strategy a, t_strategy_runtime b, t_stockinfo c
        WHERE 
            a.id = b.strategy_id and 
            b.code = c.code and 
            a.name = '{request.GET.get('name')}' and 
            (c.name like '%{searchText}%' or c.code like '%{searchText}%') and
            {formulaCondition} 
            
        order by {sortName} {sortOrder}
        limit {request.GET.get('pageSize')}
        offset {(int(request.GET.get('pageNumber'))-1)*int(request.GET.get('pageSize'))}
    ;""")
    query_result = list()
    for row in cursor.fetchall():
        dtQuotaResult = row[8]
        dtQuotaChineseResult = dict()
        for k in dtQuotaResult:
            chinese = SwitchKeyWord([k], bToID=False)[0][0]
            dtQuotaChineseResult[chinese] = dtQuotaResult[k]

        query_result.append({
            'id': row[0],
            'strategy_name': row[1],
            'status': '正常' if row[2] == 0 else "异常",
            'schedule': float(row[3]),
            'stock': row[4],
            'pass': round(float(len(row[5])/(len(row[5])+len(row[6])))*100, 0) if len(row[5])+len(row[6]) != 0 else 0,
            'time': row[7].strftime("%Y-%m-%d %H:%M:%S"),
            'success': SwitchKeyWord(row[5], bToID=False)[0],
            'failed': SwitchKeyWord(row[6], bToID=False)[0],
            'quota': dtQuotaChineseResult
        })
    cursor.execute(f"""
        select 
            count(1)
        from 
            t_strategy a, t_strategy_runtime b, t_stockinfo c
        WHERE 
            a.id = b.strategy_id and 
            b.code = c.code and 
            a.name = '{request.GET.get('name')}' and
            (c.name like '%{searchText}%' or c.code like '%{searchText}%') and
            {formulaCondition}
    ;""")

    return HttpResponse(json.dumps({
        'rows': query_result,
        'total': cursor.fetchall()[0][0]
    }), content_type="application/json")


def QueryLikePrimary(request):
    """
        通过结果，获取数据库中的指标数据，进行模糊查询，返回json列表
        query， 查询文本
    """
    query_result = list()

    word = request.GET.get('q', '').replace(":", "")

    cursor = connection.cursor()
    cursor.execute(f"""
    select '$'||name
    from t_report_quota
    WHERE position('{word}' in name) != 0
union
    select '&'||name
    from t_market_keyword
    WHERE position('{word}' in name) != 0
union
    select '@'||name
    from t_quota
    WHERE position('{word}' IN name) != 0 limit 10;""")

    start_index = 1
    for item in cursor.fetchall():
        query_result.append({
            'name': item[0], 'id': start_index
        })
        start_index += 1
    return HttpResponse(json.dumps(query_result), content_type="application/json")


def QueryTable(request, name):
    query = request.GET.get('query', '')
    cursor = connection.cursor()
    if "quota" in name:
        cursor.execute(
            f"select id, name, formula from t_quota WHERE name like '%{query}%' ORDER BY id DESC LIMIT 30")
    else:
        cursor.execute(
            f"select id, name, formulas from t_strategy WHERE name like '%{query}%' ORDER BY id DESC LIMIT 30;")

    res = list()
    for row in cursor.fetchall():
        res.append({
            'id': row[0],
            'name': row[1],
            'formula': SwitchKeyWord(row[2] if isinstance(row[2], list) else [row[2]], bToID=False)[0]
        })
    return HttpResponse(json.dumps(res), content_type="application/json")


def CommitInsert(request, name):
    cursor = connection.cursor()
    if "quota" in name:
        name = request.POST.get('name')
        formulas, sources = SwitchKeyWord([request.POST.get('formula')])
        formula = formulas[0]
        sources = ",".join(map(lambda x: f"'{x}'", sources))
        if "&" in "".join(sources):
            market = 1
        else:
            market = 0

        cursor.execute(f"""
                    INSERT INTO t_quota(name, formula, sources, market, status) 
                                VALUES ('{name}', '{formula}', ARRAY[{sources}], '{market}', '1');
                """)
    else:
        name = f"'{request.POST.get('name')}'"
        formulas, _ = SwitchKeyWord(request.POST.get('formula').split('|'))
        formulas = ",".join(map(lambda x: f"'{x}'", formulas))

        cursor.execute(f"INSERT INTO t_strategy(name, formulas) VALUES ({name}, ARRAY[{formulas}]);")
    return HttpResponse(json.dumps({"code": 0, "msg": "success"}), content_type="application/json")


def CommitUpdate(request, name):
    cursor = connection.cursor()
    if "quota" in name:
        formulas, sources = SwitchKeyWord([request.POST.get('formula')])
        formula = formulas[0]
        sources = ",".join(map(lambda x: f"'{x}'", sources))
        if "&" in "".join(sources):
            market = 1
        else:
            market = 0
        cursor.execute(f"""
            UPDATE t_quota SET 
                name='{request.POST.get('name')}', 
                formula = '{formula}',
                sources = ARRAY[{sources}],
                market = '{market}'
            WHERE 
                id='{request.POST.get('id')}';
        """)
    else:
        formulas, _ = SwitchKeyWord(request.POST.get('formula').split('|'))
        formulas = ",".join(map(lambda x: f"'{x}'", formulas))
        cursor.execute(f"""
            UPDATE t_strategy SET 
                name='{request.POST.get('name')}', 
                formulas = ARRAY[{formulas}] 
            WHERE 
                id='{request.POST.get('id')}';
        """)

    return HttpResponse(json.dumps({'code': 0, 'msg': 'success'}), content_type="application/json")


def CommitDelete(request, name, id):
    cursor = connection.cursor()
    if "quota" in name:
        cursor.execute(f"delete from t_quota where id={id};")
        cursor.execute(f"delete from t_strategy where array_to_string(formulas, ',') like '@{id}%';")
    else:
        cursor.execute(f"delete from t_strategy where id={id};")
    return HttpResponse(json.dumps({'code': 0, 'msg': 'success'}), content_type="application/json")


def ToChinese():
    dtKeyWord = {}
    cursor = connection.cursor()

    cursor.execute("select id, '@'||name from t_quota;")
    for row in cursor.fetchall():
        dtKeyWord.setdefault(f'@{row[0]}', row[1])

    cursor.execute("select id, '$'||name from t_report_quota;")
    for row in cursor.fetchall():
        dtKeyWord.setdefault(f'${row[0]}', row[1])

    cursor.execute("select pos, '&'||name from t_market_keyword;")
    for row in cursor.fetchall():
        dtKeyWord.setdefault(f'&{row[0]}', row[1])

    return dtKeyWord


def ToKeyWord():
    dtKeyWord = {}
    cursor = connection.cursor()

    cursor.execute("SELECT id, '@'||name FROM t_quota;")
    for row in cursor.fetchall():
        dtKeyWord.setdefault(row[1], f'@{row[0]}')

    cursor.execute("select id, '$'||name from t_report_quota;")
    for row in cursor.fetchall():
        dtKeyWord.setdefault(row[1], f'${row[0]}')

    cursor.execute("select '&'||name, pos from t_market_keyword;")
    for row in cursor.fetchall():
        dtKeyWord.setdefault(row[0], f'&{row[1]}')

    return dtKeyWord


def SwitchKeyWord(formulas, bToID=True, toChinese=ToChinese, toID=ToKeyWord):
    formulas_vert = []
    sources = []
    if bToID:
        diction = toID()
    else:
        diction = toChinese()

    for formula in formulas:
        str_new_formula = ""
        for keyword in formula.split(' '):
            if str_new_formula:
                str_new_formula += ' '

            k = re.findall(r"([&$@].*?)[\[?]", keyword+'[')
            if k and k[0] in diction:
                sources.append(keyword.replace(k[0], diction[k[0]]))
            str_new_formula += diction.get(keyword, keyword)
        formulas_vert.append(str_new_formula)
    return formulas_vert, sources


def market(request):
    cli = Outer().get_cli()

    jump = 0
    now = datetime.datetime.now()
    while len(cli.keys(f"AMM:{now.strftime('%Y-%m-%d')}:*")) == 0 and jump < 10:
        now -= datetime.timedelta(days=1)
        jump += 1

    if jump == 10:
        return HttpResponse(json.dumps({'ret': False}), content_type="application/json")

    detail = {
        'turnover': {},
        'voturnover': {},
        'vaturnover': {},
        'mcap': {},
    }
    total = {
        'turnover': 0,
        'voturnover': 0,
        'vaturnover': 0,
        'mcap': 0,
    }
    for key in cli.keys(f"AMM:{now.strftime('%Y-%m-%d')}:*"):
        data = json.loads(cli.get(key).decode())
        name = key.decode().split(':')[-1]
        detail['turnover'].setdefault(name, data['turnover'])
        detail['voturnover'].setdefault(name, data['voturnover'])
        detail['vaturnover'].setdefault(name, data['vaturnover'])
        detail['mcap'].setdefault(name, data['mcap'])
        total['turnover'] += data['turnover']
        total['voturnover'] += data['voturnover']
        total['vaturnover'] += data['vaturnover']
        total['mcap'] += data['mcap']

    for field in detail:
        for name in detail[field]:
            if field == 'turnover':
                detail[field][name] = round(detail[field][name], 2)
            else:
                detail[field][name] = round(detail[field][name]/100000000, 2)
        detail[field] = dict(sorted(detail[field].items(), key=lambda x: x[1], reverse=True)[:request.POST.get('limit', 15)])

    return HttpResponse(json.dumps({'ret': True, 'data': detail}), content_type="application/json")


def market_detail(request):
    # industry, field, st, ed
    name = request.POST.get('industry')
    field = request.POST.get('field')
    st = datetime.datetime.strptime(request.POST.get('st'), '%Y-%m-%d')
    ed = datetime.datetime.strptime(request.POST.get('ed'), '%Y-%m-%d')
    cli = Outer().get_cli()
    yAxis = []
    xAxis = []
    while st <= ed:
        data = cli.get(f"AMM:{st.strftime('%Y-%m-%d')}:{name}")
        if data:
            value_json = json.loads(data.decode())
            xAxis.append(st.strftime('%Y-%m-%d'))
            if field == 'turnover':
                yAxis.append(round(value_json[field], 1))
            else:
                yAxis.append(round(value_json[field]/100000000, 1))
        st += datetime.timedelta(days=1)
    return HttpResponse(json.dumps({'xAxis': xAxis, 'yAxis': yAxis,
                                    'name': name, 'field': field}), content_type="application/json")

